package com.egao.common.module.student.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.egao.common.core.web.PageParam;
import com.egao.common.core.web.PageResult;
import com.egao.common.module.company.entity.Company;
import com.egao.common.module.company.entity.Preach;
import com.egao.common.module.company.entity.PreachCloud;
import com.egao.common.module.company.entity.Recruit;
import com.egao.common.module.company.mapper.CompanyMapper;
import com.egao.common.module.company.mapper.PreachCloudMapper;
import com.egao.common.module.company.mapper.PreachMapper;
import com.egao.common.module.company.mapper.RecruitMapper;
import com.egao.common.module.push.entity.PushMsg;
import com.egao.common.module.push.mapper.PushMsgMapper;
import com.egao.common.module.student.constants.StudentRecommendConstants;
import com.egao.common.module.student.entity.vo.StudentOperRecordVO;
import com.egao.common.module.student.entity.vo.StudentRecommendCompanyVO;
import com.egao.common.module.student.entity.vo.StudentRecommendVO;
import com.egao.common.module.student.service.StudentRecommendService;
import com.egao.common.module.system.entity.OperRecord;
import com.egao.common.module.system.mapper.OperRecordMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;


/**
 * 学生推荐信息接口实现类
 *
 * @author dl
 */
@Service
@Slf4j
public class StudentRecommendServiceImpl extends ServiceImpl<PushMsgMapper, PushMsg> implements StudentRecommendService {

    @Autowired
    private OperRecordMapper operRecordMapper;

    @Autowired
    private RecruitMapper recruitMapper;

    @Autowired
    private PreachMapper preachMapper;

    @Autowired
    private PreachCloudMapper preachCloudMapper;

    @Autowired
    private CompanyMapper companyMapper;

    @Override
    public PageResult<StudentRecommendVO> listPage(PageParam<StudentRecommendVO> pageParam) {
        return new PageResult<>(baseMapper.selectByStudentId(pageParam), pageParam.getTotal());
    }

    /**
     * 猜你喜欢，需要30条信息
     *
     *   1. 根据学生浏览单位发布信息记录，通过信息编号查询对应单位发布信息（招聘、校内宣讲会、空中宣讲会）。
     *   2. 如果单位发布信息数量小于30条时，需要关联浏览单位所在省份、所在城市、规模、行业、单位性质查询关联查询其他相同所在省份、所在城市、规模、行业、单位性质单位发布的信息。
     *   3. 如果发布信息数量仍然小于30条时，查询最新发布的信息。
     *
     * @param page 查询条件、分页参数
     * @return
     */
    @Override
    public List<StudentRecommendVO> getStudentRecommend(PageParam<StudentRecommendVO> page) {
        // 查询学生浏览记录
        List<OperRecord> operRecordList = operRecordMapper.selectList(new QueryWrapper<OperRecord>().eq("user_id", page.get("userId")).eq("description", "查询详情").in("model", getModelList()));

        // 学生的浏览记录为空
        if (operRecordList.isEmpty() || operRecordList.size() == 0) {
            return getInfoList(StudentRecommendConstants.RECOMMEND_TOTAL);
        }
        // 学生浏览的招聘、宣讲会、空中宣讲会、除去重复记录
        List<StudentOperRecordVO> studentOperRecordVOList = filterStudentOperRecord(operRecordList);
        if (studentOperRecordVOList == null) {
            return getInfoList(StudentRecommendConstants.RECOMMEND_TOTAL);
        }
        // 查询完整浏览信息
        List<StudentRecommendVO> operRecomendList = queryStudentRecommendVOById(studentOperRecordVOList, null);
        // 学生的浏览记录为空
        if (operRecomendList.isEmpty() || operRecomendList.size() == 0) {
            return getInfoList(StudentRecommendConstants.RECOMMEND_TOTAL);
        }
        // 通过浏览记录得到单位编号
        List<Integer> companyIdList = getCompanyIdList(operRecomendList);
        // 查询单位发布有效信息
        List<StudentRecommendVO> operRecomendCompanyList = getStudentRecommendVO(companyIdList, StudentRecommendConstants.VALID);

        int companyNumber = operRecomendCompanyList.size();
        // 如果学生浏览招聘信息数量大于30，返回30条数据
        // 单位没有发布有效信息，直接查询最新的30个校园招聘信息
        if (companyNumber >= StudentRecommendConstants.RECOMMEND_TOTAL) {
            return getInfoList(operRecomendCompanyList);
        }

        // 单位发布的信息数量不够，需要查询相同单位行业、性质、规模、所在城市单位
        // 查询相同单位数量
        List<Integer> newCompanyIdList = getRelationCompany(companyIdList);
        if (newCompanyIdList == null) {
            return null;
        }
        // 去掉浏览的单位
        newCompanyIdList.removeAll(companyIdList);
        // 相关单位信息
        List<StudentRecommendVO> studentRecommendVOList =  getStudentRecommendVO(newCompanyIdList, StudentRecommendConstants.VALID);
        int withCompanyNumber = studentRecommendVOList.size();
        // 需要推荐信息个数
        int needNumber = StudentRecommendConstants.RECOMMEND_TOTAL - companyNumber;
        // 相关单位数量足够
        if (withCompanyNumber >= needNumber) {
            List<StudentRecommendVO> needList = new ArrayList<>();
            List<StudentRecommendVO> sortList = sortBusinessDateASC(studentRecommendVOList);
            for (int i = 0; i < needNumber; i++) {
                needList.add(sortList.get(i));
            }
            operRecomendCompanyList.addAll(needList);
            return sortBusinessDateASC(operRecomendList);
        }
        operRecomendCompanyList.addAll(studentRecommendVOList);

        // 剩余需要个数
        int surplus = needNumber - withCompanyNumber;
        List<StudentRecommendVO> surplusList = getInfoList(surplus);
        if (surplusList != null) {
            operRecomendCompanyList.addAll(surplusList);
        }
        return sortBusinessDateASC(operRecomendCompanyList);
    }

    /**
     * 最新发布的招聘信息
     *
     * @param operRecomendList 信息数量不够
     * @return
     */
    private List<StudentRecommendVO> getInfoList(List<StudentRecommendVO> operRecomendList) {
        List<StudentRecommendVO> newList = new ArrayList<>();
        // 数量足够
        if (operRecomendList.size() >= StudentRecommendConstants.RECOMMEND_TOTAL) {
            List<StudentRecommendVO> needList = sortBusinessDateASC(operRecomendList);
            for (int i = 0; i < StudentRecommendConstants.RECOMMEND_TOTAL; i++) {
                newList.add(needList.get(i));
            }
            return newList;
        }
        // 数量不够
        return getInfoList(operRecomendList, StudentRecommendConstants.RECOMMEND_TOTAL - operRecomendList.size());
    }

    /**
     * 最新发布的招聘信息
     *
     * @param operRecomendList 信息数量不够
     * @return
     */
    private List<StudentRecommendVO> getInfoList(List<StudentRecommendVO> operRecomendList, int len) {
        List<StudentRecommendVO> newList = getInfoList(len);
        operRecomendList.addAll(newList);
        return sortBusinessDateASC(operRecomendList);
    }

    /**
     * 最新发布的招聘信息
     *
     * @param len 获取数量
     * @return
     */
    private List<StudentRecommendVO> getInfoList(int len) {
        List<StudentRecommendVO> studentRecommendVOList = getStudentRecommendVO(null, StudentRecommendConstants.VALID);
        if (studentRecommendVOList == null || studentRecommendVOList.size() == 0) {
            return null;
        }
        List<StudentRecommendVO> sortList = sortBusinessDateASC(studentRecommendVOList);
        int sortLen = sortList.size();
        if (sortLen < len) {
            len = sortLen;
        }
        List<StudentRecommendVO> needList = new ArrayList<>();
        for (int i = 0; i < len; i++) {
            needList.add(sortList.get(i));
        }
        return needList;
    }

    /**
     * 查询相关单位
     *
     * @param companyIdList 单位编号
     * @return
     */
    private List<Integer> getRelationCompany(List<Integer> companyIdList) {
        Map<String, Object> map = new HashMap<>(16);
        map.put("companyList", companyIdList);
        // 查询单位行业、性质、规模、所在城市单位
        List<Company> companies = companyMapper.getCompanyIdByCondition(map);
        List<Company> newCompanyList = new ArrayList<>();
        for (Company company : companies) {
            Map<String, Object> conMap = new HashMap<>(16);
            conMap.put("province", company.getProvince());
            conMap.put("city", company.getCity());
            conMap.put("scale", company.getScale());
            conMap.put("industry", company.getIndustry());
            conMap.put("nature", company.getNature());
            List<Company> cList = companyMapper.getCompanyIdByCondition(conMap);
            if (cList != null && cList.size() > 0) {
                newCompanyList.addAll(cList);
            }
        }
        if (newCompanyList.size() == 0) {
            return null;
        }
        List<Integer> newCompanyIdList = new ArrayList<>();
        for (Company company : newCompanyList) {
            newCompanyIdList.add(company.getId());
        }
        return newCompanyIdList;
    }


    /**
     * 根据发布时间顺序
     *
     * @param studentRecommendVOList
     * @return
     */
    private List<StudentRecommendVO> sortBusinessDateASC(List<StudentRecommendVO> studentRecommendVOList) {
        return studentRecommendVOList.stream().sorted(Comparator.comparing(StudentRecommendVO::getBusinessDateLong)).collect(Collectors.toList());
    }

    /**
     * 查询浏览的单位
     *
     * @param operRecomendList
     * @return
     */
    private List<Integer> getCompanyIdList(List<StudentRecommendVO> operRecomendList) {
        List<Integer> companyList = new ArrayList<>();
        for (StudentRecommendVO sr : operRecomendList) {
            companyList.add(sr.getCompanyId());
        }
        return companyList.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 获取需要查询的操作记录（招聘、宣讲会、空中）
     *
     * @return
     */
    private List<String> getModelList() {
        List<String> list = new ArrayList<>();
        list.add(StudentRecommendConstants.MODEL_RECRUIT);
        list.add(StudentRecommendConstants.MODEL_PREACH);
        list.add(StudentRecommendConstants.MODEL_PREACH_CLOUD);
        return list;
    }

    /**
     * 过滤操作记录，提取不重复的（招聘、宣讲会、空中）
     *
     * @param operRecordList 操作记录
     * @return
     */
    private List<StudentOperRecordVO> filterStudentOperRecord(List<OperRecord> operRecordList) {
        List<StudentOperRecordVO> operRecordVOList = new ArrayList<>();
        for (OperRecord operRecord : operRecordList) {
            StudentOperRecordVO so = new StudentOperRecordVO();
            String type = StudentRecommendConstants.getType(operRecord.getModel());
            if (type == null) {
                continue;
            }
            Integer businessId = getBusinessId(operRecord.getParam());
            if (businessId == null) {
                continue;
            }
            so.setType(type);
            so.setBusinessId(businessId);
            operRecordVOList.add(so);
        }
        if (operRecordVOList.size() > 0) {
            return operRecordVOList.stream().distinct().collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 获取操作记录中的业务编号
     *
     * @param idJson 参数
     * @return
     */
    private Integer getBusinessId(String idJson) {
        Integer businessId = null;
        try {
            if (JSONUtil.isJson(idJson) && idJson.contains(StudentRecommendConstants.PARAM)) {
                JSONObject jsonObject = JSONUtil.parseObj(idJson);
                String ids = jsonObject.getStr(StudentRecommendConstants.PARAM);
                if (JSONUtil.isJsonArray(ids)) {
                    JSONArray array = JSONUtil.parseArray(ids);
                    if (array.size() > 0) {
                        String id = (String) array.get(0);
                        businessId = Integer.parseInt(id);
                    }
                }
            }
        } catch (Exception e) {
            return businessId;
        }
        return businessId;
    }

    /**
     * 查询推荐具体信息
     *
     * @param operRecordVOList
     * @return
     */
    private List<StudentRecommendVO> queryStudentRecommendVOById(List<StudentOperRecordVO> operRecordVOList, String valid) {
        // 找出各个业务编号集合
        List<Integer> recruit = new ArrayList<>();
        List<Integer> preach = new ArrayList<>();
        List<Integer> preachCloud = new ArrayList<>();
        for (StudentOperRecordVO so : operRecordVOList) {
            if (StudentRecommendConstants.MODEL_RECRUIT_TYPE.equals(so.getType())) {
                recruit.add(so.getBusinessId());
            }
            if (StudentRecommendConstants.MODEL_PREACH_TYPE.equals(so.getType())) {
                preach.add(so.getBusinessId());
            }
            if (StudentRecommendConstants.MODEL_PREACH_CLOUD_TYPE.equals(so.getType())) {
                preachCloud.add(so.getBusinessId());
            }
        }
        // 根据业务编号查询
        List<StudentRecommendVO> studentRecommendVOList = getStudentRecommendVO(recruit, preach, preachCloud, valid);
        return studentRecommendVOList;
    }

    private List<StudentRecommendVO> getStudentRecommendVO(List<Integer> recruit, List<Integer> preach, List<Integer> preachCloud, String valid) {
        List<StudentRecommendVO> studentRecommendVOList = new ArrayList<>();
        if (recruit.size() > 0) {
            Map<String, Object> map = new HashMap<>(16);
            map.put("list", recruit);
            List<Recruit> recruitList = recruitMapper.getRecruitByIds(map);
            convertToStudentRecommend(studentRecommendVOList, recruitList, null, null);
        }
        if (preach.size() > 0) {
            Map<String, Object> map = new HashMap<>(16);
            map.put("list", preach);
            List<Preach> preachList = preachMapper.getPreachByIds(map);
            convertToStudentRecommend(studentRecommendVOList, null, preachList, null);
        }
        if (preachCloud.size() > 0) {
            Map<String, Object> map = new HashMap<>(16);
            map.put("list", preachCloud);
            List<PreachCloud> preachCloudList = preachCloudMapper.getPreachCloudByIds(map);
            convertToStudentRecommend(studentRecommendVOList, null, null, preachCloudList);
        }
        return studentRecommendVOList;
    }

    /**
     * 根据编号查询发布信息
     *
     * @param companyIdList  招聘
     * @param valid      宣讲会
     * @return
     */
    private List<StudentRecommendVO> getStudentRecommendVO(List<Integer> companyIdList, String valid) {
        List<StudentRecommendVO> studentRecommendVOList = new ArrayList<>();
        Map<String, Object> map = new HashMap<>(16);
        map.put("valid", valid);
        if (companyIdList != null && companyIdList.size() > 0) {
            map.put("companyList", companyIdList);
        }
        List<Recruit> recruitList = recruitMapper.getRecruitByIds(map);
        convertToStudentRecommend(studentRecommendVOList, recruitList, null, null);
        List<Preach> preachList = preachMapper.getPreachByIds(map);
        convertToStudentRecommend(studentRecommendVOList, null, preachList, null);
        List<PreachCloud> preachCloudList = preachCloudMapper.getPreachCloudByIds(map);
        convertToStudentRecommend(studentRecommendVOList, null, null, preachCloudList);
        return studentRecommendVOList;
    }

    /**
     * 获取推荐信息
     *
     * @param studentRecommendVOList
     * @param recruitList
     * @param preachList
     * @param preachCloudList
     * @return
     */
    private List<StudentRecommendVO> convertToStudentRecommend(List<StudentRecommendVO> studentRecommendVOList, List<Recruit> recruitList, List<Preach> preachList, List<PreachCloud> preachCloudList) {
        if (recruitList != null && recruitList.size() > 0) {
            for (Recruit recruit : recruitList) {
                StudentRecommendVO sr = new StudentRecommendVO();
                sr.setId(StudentRecommendConstants.MODEL_RECRUIT_TYPE + "-" + recruit.getId());
                sr.setBusinessId(recruit.getId());
                sr.setRecruitType(recruit.getType());
                sr.setType(StudentRecommendConstants.MODEL_RECRUIT_TYPE);
                sr.setTypeName(StudentRecommendConstants.MODEL_RECRUIT);
                sr.setTitle(recruit.getTitle());
                sr.setCompanyName(recruit.getCompanyName());
                sr.setBusinessDate(recruit.getValidTime());
                sr.setCompanyId(recruit.getCompanyId());
                sr.setBusinessDateLong(recruit.getValidTime().getTime());
                studentRecommendVOList.add(sr);
            }
        }
        if (preachList != null && preachList.size() > 0) {
            for (Preach preach : preachList) {
                StudentRecommendVO sr = new StudentRecommendVO();
                sr.setId(StudentRecommendConstants.MODEL_PREACH_TYPE + "-" + preach.getId());
                sr.setBusinessId(preach.getId());
                sr.setType(StudentRecommendConstants.MODEL_PREACH_TYPE);
                sr.setTypeName(StudentRecommendConstants.MODEL_PREACH);
                sr.setTitle(preach.getTitle());
                sr.setCompanyName(preach.getCompanyName());
                sr.setBusinessDate(preach.getHoldTime());
                sr.setCompanyId(preach.getCompanyId());
                sr.setBusinessDateLong(preach.getHoldTime().getTime());
                studentRecommendVOList.add(sr);
            }
        }
        if (preachCloudList != null && preachCloudList.size() > 0) {
            for (PreachCloud preachCloud : preachCloudList) {
                StudentRecommendVO sr = new StudentRecommendVO();
                sr.setBusinessId(preachCloud.getId());
                sr.setId(StudentRecommendConstants.MODEL_PREACH_CLOUD_TYPE + "-" + preachCloud.getId());
                sr.setType(StudentRecommendConstants.MODEL_PREACH_CLOUD_TYPE);
                sr.setTypeName(StudentRecommendConstants.MODEL_PREACH_CLOUD);
                sr.setTitle(preachCloud.getTitle());
                sr.setCompanyName(preachCloud.getCompanyName());
                sr.setBusinessDate(preachCloud.getHoldTime());
                sr.setCompanyId(preachCloud.getCompanyId());
                sr.setBusinessDateLong(preachCloud.getHoldTime().getTime());
                studentRecommendVOList.add(sr);
            }
        }
        return studentRecommendVOList;
    }

}
